extern crate collections;
use hammer::{FlagConfig,FlagConfiguration};
-use std::{os,io};
-use serialize::{Decodable,Encodable,json};
-use cargo::{CargoResult,ToCargoError,NoFlags,execute_main_without_stdin,process_executed,handle_error};
+use std::os;
+use serialize::Encodable;
+use cargo::{CargoResult,ToCargoError,NoFlags,execute_main_without_stdin,handle_error};
use cargo::util::important_paths::find_project;
use cargo::util::config;
root: ~str
}
+/**
+ The top-level `cargo` command handles configuration and project location
+ because they are fundamental (and intertwined). Other commands can rely
+ on this top-level information.
+*/
fn execute() {
- let (cmd, args) = match process(os::args()) {
+ let (cmd, _) = match process(os::args()) {
Ok((cmd, args)) => (cmd, args),
Err(err) => return handle_error(err)
};
- if cmd == ~"config" { execute_main_without_stdin(config) }
+ if cmd == ~"config-for-key" { execute_main_without_stdin(config_for_key) }
+ else if cmd == ~"config-list" { execute_main_without_stdin(config_list) }
else if cmd == ~"locate-project" { execute_main_without_stdin(locate_project) }
}
Ok((head, tail))
}
+#[deriving(Encodable)]
+struct ConfigOut {
+ values: collections::HashMap<~str, config::ConfigValue>
+}
+
#[deriving(Decodable)]
-struct ConfigFlags {
+struct ConfigForKeyFlags {
key: ~str,
- value: Option<~str>,
human: bool
}
-impl FlagConfig for ConfigFlags {
- fn config(_: Option<ConfigFlags>, c: FlagConfiguration) -> FlagConfiguration {
- c.short("human", 'h')
+impl FlagConfig for ConfigForKeyFlags {
+ fn config(_: Option<ConfigForKeyFlags>, config: FlagConfiguration) -> FlagConfiguration {
+ config.short("human", 'h')
}
}
-#[deriving(Encodable)]
-struct ConfigOut {
- values: collections::HashMap<~str, config::ConfigValue>
-}
-
-fn config(args: ConfigFlags) -> CargoResult<Option<ConfigOut>> {
+fn config_for_key(args: ConfigForKeyFlags) -> CargoResult<Option<ConfigOut>> {
let value = try!(config::get_config(os::getcwd(), args.key.as_slice()));
if args.human {
}
}
-fn locate_project(args: NoFlags) -> CargoResult<Option<ProjectLocation>> {
+#[deriving(Decodable)]
+struct ConfigListFlags {
+ human: bool
+}
+
+impl FlagConfig for ConfigListFlags {
+ fn config(_: Option<ConfigListFlags>, config: FlagConfiguration) -> FlagConfiguration {
+ config.short("human", 'h')
+ }
+}
+
+fn config_list(args: ConfigListFlags) -> CargoResult<Option<ConfigOut>> {
+ let configs = try!(config::all_configs(os::getcwd()));
+
+ if args.human {
+ for (key, value) in configs.iter() {
+ println!("{} = {}", key, value);
+ }
+ Ok(None)
+ } else {
+ Ok(Some(ConfigOut { values: configs }))
+ }
+}
+
+fn locate_project(_: NoFlags) -> CargoResult<Option<ProjectLocation>> {
let root = try!(find_project(os::getcwd(), ~"Cargo.toml"));
let string = try!(root.as_str().to_cargo_error(format!("Your project path contains characters not representable in Unicode: {}", os::getcwd().display()), 1));
Ok(Some(ProjectLocation { root: string.to_owned() }))
+extern crate collections;
extern crate toml;
-use super::super::{CargoResult,CargoError,ToCargoError};
+use super::super::{CargoResult,ToCargoError};
use std::{io,fmt};
-#[deriving(Eq,Clone,Encodable,Decodable)]
+#[deriving(Eq,TotalEq,Clone,Encodable,Decodable)]
pub enum Location {
Project,
Global
}
-#[deriving(Eq,Clone,Encodable,Decodable)]
+#[deriving(Eq,TotalEq,Clone,Encodable,Decodable)]
pub struct ConfigValue {
value: ~str,
path: ~str
}
pub fn get_config(pwd: Path, key: &str) -> CargoResult<ConfigValue> {
- walk_tree(&pwd, |file| extract_config(file, key)).to_cargo_error(format!("Config key not found: {}", key), 1)
+ find_in_tree(&pwd, |file| extract_config(file, key)).to_cargo_error(format!("Config key not found: {}", key), 1)
}
+pub fn all_configs(pwd: Path) -> CargoResult<collections::HashMap<~str, ConfigValue>> {
+ let mut map = collections::HashMap::new();
+
+ walk_tree(&pwd, |file| {
+ let _ = extract_all_configs(file).map(|configs| {
+ for (key, value) in configs.move_iter() {
+ map.find_or_insert(key, value);
+ }
+ });
+ });
+
+ Ok(map)
+}
+
+#[allow(unused_variable)]
pub fn set_config(key: ~str, value: ~str, location: Location) -> CargoResult<()> {
Ok(())
}
-fn walk_tree<T>(pwd: &Path, walk: |io::fs::File| -> CargoResult<T>) -> Option<T> {
+fn find_in_tree<T>(pwd: &Path, walk: |io::fs::File| -> CargoResult<T>) -> Option<T> {
let mut current = pwd.clone();
loop {
None
}
+fn walk_tree(pwd: &Path, walk: |io::fs::File| -> ()) {
+ let mut current = pwd.clone();
+
+ loop {
+ let possible = current.join(".cargo").join("config");
+ if possible.exists() {
+ let _ = io::fs::File::open(&possible).map(|file| walk(file));
+ }
+
+ if !current.pop() { break; }
+ }
+}
+
fn extract_config(file: io::fs::File, key: &str) -> CargoResult<ConfigValue> {
let path = try!(file.path().as_str().to_cargo_error(~"", 1)).to_owned();
let mut buf = io::BufferedReader::new(file);
let val = try!(try!(root.lookup(key).to_cargo_error(~"", 1)).get_str().to_cargo_error(~"", 1));
Ok(ConfigValue{ value: val.to_owned(), path: path })
}
+
+fn extract_all_configs(file: io::fs::File) -> CargoResult<collections::HashMap<~str, ConfigValue>> {
+ let mut map = collections::HashMap::new();
+
+ let path = try!(file.path().as_str().to_cargo_error(~"", 1)).to_owned();
+ let mut buf = io::BufferedReader::new(file);
+ let root = try!(toml::parse_from_buffer(&mut buf).to_cargo_error(~"", 1));
+ let table = try!(root.get_table().to_cargo_error(~"", 1));
+
+ for (key, value) in table.iter() {
+ match value {
+ &toml::String(ref val) => { map.insert(key.to_owned(), ConfigValue { value: val.to_owned(), path: path.clone() }); }
+ _ => ()
+ }
+ }
+
+ Ok(map)
+}